/*
 * COPYRIGHT:	2010 Christopher Smith, licenced under the GNU GPL v2; see COPYING in the top level directory
 * PROJECT:		sdedit
 * FILE:		rtl.cpp
 * PURPOSE:		various Rtl style support functions
 *				
 */

//where c is the class in question, use macro inside class body
#define NO_ASSIGNMENT_OPERATOR(c) __declspec(deprecated("This class does not support assignment")) c const &operator=(c const &) const;
#define NO_COPY_CONSTRUCTOR(c) __declspec(deprecated("This class does not support copying")) c(c const &);

template <class T> void FORCEINLINE RtlZeroSizedStruct(T &x)
{
	RtlZeroMemory(&x, sizeof x);
	x.Size = sizeof x;
}

template <class T> void FORCEINLINE RtlZeroLengthedStruct(T &x)
{
	RtlZeroMemory(&x, sizeof x);
	x.Length = sizeof x;
}

template <class T> void FORCEINLINE RtlZeroStruct(T &x)
{
	RtlZeroMemory(&x, sizeof x);
}

void FORCEINLINE RtlInitUnicodeString(UNICODE_STRING *ucs, PWSTR str)
{
	ucs->Buffer = str;

	if(str)
		ucs->Length = ucs->MaximumLength = narrowing_cast<USHORT>(wcslen(str) * sizeof(WCHAR));
	else
		ucs->Length = ucs->MaximumLength = 0;
}

void FORCEINLINE RtlInitObjectAttributes(OBJECT_ATTRIBUTES *oa, HANDLE RootDirectory OPTIONAL, UNICODE_STRING *ObjectName OPTIONAL, ULONG Attributes, SECURITY_DESCRIPTOR *SecurityDescriptor OPTIONAL, SECURITY_QUALITY_OF_SERVICE *SecurityQualityOfService OPTIONAL)
{
	oa->Length = sizeof(OBJECT_ATTRIBUTES);
	oa->RootDirectory = RootDirectory;
	oa->ObjectName = ObjectName;
	oa->Attributes = Attributes;
	oa->SecurityDescriptor = SecurityDescriptor;
	oa->SecurityQualityOfService = SecurityQualityOfService;
}

//call init, cleanup during module init, cleanup
//create object on stack to associate event with thread
ULONG ThreadSynchEventTlsIndex = 0;

struct ThreadSynchEvent
{
	static void InitThreadSynchEvents()
	{
		ThreadSynchEventTlsIndex = TlsAlloc();
	}

	static void CleanupThreadSynchEvents()
	{
		TlsFree(ThreadSynchEventTlsIndex);
	}

	ThreadSynchEvent()
	{
		TlsSetValue(ThreadSynchEventTlsIndex, NULL);
	}
	~ThreadSynchEvent()
	{
		HANDLE Event = c_cast<HANDLE>(TlsGetValue(ThreadSynchEventTlsIndex));

		if(Event)
			CloseHandle(Event);

		TlsSetValue(ThreadSynchEventTlsIndex, NULL);
	}
};

//must already have ThreadSynchEvent obj created for thread
HANDLE RtlThreadSynchEvent()
{
	HANDLE Event = c_cast<HANDLE>(TlsGetValue(ThreadSynchEventTlsIndex));

	if(Event)
		return Event;
	else
	{
		Event = CreateEvent(NULL, TRUE, TRUE, NULL);
		TlsSetValue(ThreadSynchEventTlsIndex, Event);
	}

	return Event;
}